using System;
using System.Runtime.InteropServices;
using System.Threading;
using WindowsAPI.Service;

namespace WindowsAPI
{
    /// <summary>Class that sets a WIN32 WaitableTimer. The timer will wake up the PC if the PC is in standby or hibernation mode.</summary>
    [CopyRight("http://pinvoke.net/default.aspx/kernel32/SetWaitableTimer.html")]
    [Link("http://uinc.ru/articles/38/")]
    public class WaitableTimer
    {

        public event Action OnTimerSet;
        public event Action OnTimerCompleted;

        private IntPtr handle;

        public void SetTimer(long Interval)
        {
            // Creating the timer delegate
            Action TimerComplete = TimerCompleted;
            Action TimerSet = TimerIsSet;

            // Creating the timer
            Console.WriteLine("Creating WaitableTimer");
            handle = Kernel32.CreateWaitableTimer(IntPtr.Zero, true, "WaitableTimer");
            Console.WriteLine("Last Error = " + Marshal.GetLastWin32Error().ToString());

            // Setting up the timer, the long Interval value needs to be negative if 
            // you want to set up a delay in milliseconds. ie 
            // if Interval = -60000000 the timer will expire in 1 minute. Once expired it runs the 
            // TimerComplete delegate
            Console.WriteLine("Setting WaitableTimer");
            Kernel32.SetWaitableTimer(handle, ref Interval, 0, TimerComplete, IntPtr.Zero, true);
            Console.WriteLine("Last Error = " + Marshal.GetLastWin32Error().ToString()); // The error may be 1004 (Invalid flags), this is not critical
            Console.WriteLine("Timer set @ " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));

            // Starting a new thread which waits for the WaitableTimer to expire
            var t_Wait = new Thread(new ThreadStart(WaitTimer));
            t_Wait.Start();

            // Raising Event Timer Set
            if(OnTimerSet != null)
                OnTimerSet();
        }

        private void WaitTimer()
        {
            // Waiting for the timer to expire
            if(Kernel32.WaitForSingleObject(handle, Consts.INFINITE) != 0)
                Console.WriteLine("Last Error = " + Marshal.GetLastWin32Error().ToString());
            else
                Console.WriteLine("Timer expired @ " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"));

            // Closing the timer
            Kernel32.CloseHandle(handle);

            // Raising event Timer Completed
            if(OnTimerCompleted != null)
                OnTimerCompleted();
        }

        private void TimerCompleted()
        {
            // Routine executed once the timer has expired. This is executed independently of the 
            // program calling this class implementation of the OnTimerCompleted Event
            //
            Console.WriteLine("Timer is complete in the class");
        }

        private void TimerIsSet()
        {
            Console.WriteLine("Timer is set in the class");
        }
    }
}